home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 4 / Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso / Development / Source / Halma 1.1.source Folder / Halma ƒ / Shell ƒ / help.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-26  |  18.0 KB  |  704 lines  |  [TEXT/KAHL]

  1. /**********************************************************************\
  2.  
  3. File:        help.c
  4.  
  5. Purpose:    This module handles displaying the different help windows.
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program in a file named "GNU General Public License".
  19. If not, write to the Free Software Foundation, 675 Mass Ave,
  20. Cambridge, MA 02139, USA.
  21.  
  22. \**********************************************************************/
  23.  
  24. #include "help.h"
  25. #include "environment.h"
  26. #include "util.h"
  27. #include "buttons.h"
  28. #include "timing.h"
  29. #include "program globals.h"
  30.  
  31. #define DEAD_SPACE_TOP        10
  32. #define DEAD_SPACE_LEFT        10
  33. #define DEAD_SPACE_BOTTOM    10
  34. #define DEAD_SPACE_RIGHT    10
  35. #define    TEXT_RECT_WIDTH        405
  36. #define    TEXT_RECT_HEIGHT    250
  37. #define    BUTTON_WIDTH        60
  38. #define    BUTTON_HEIGHT        60
  39.  
  40. #define MAX_MAIN_TOPICS        5
  41. #define    MAX_SUB_TOPICS        6
  42.  
  43. #define MAIN_TOPIC_ID        600
  44. #define FIRST_SUB_TOPIC_ID    610
  45. #define FIRST_TEXT_ID        400
  46.  
  47. #define theWindowWidth (boundsRect.right-boundsRect.left)
  48. #define theWindowHeight (boundsRect.bottom-boundsRect.top)
  49. #define CorrectTime 1
  50. #define SCROLL_BOX_SIZE        20
  51.  
  52. typedef unsigned char    **CharHandle;
  53.  
  54. typedef struct
  55. {
  56.     long            offset;
  57.     short            lineHeight;
  58.     short            fontDescent;
  59.     short            fontNum;
  60.     unsigned char    fontStyle;
  61.     unsigned char    unused1;
  62.     short            fontSize;
  63.     short            unused2;
  64.     short            unused3;
  65.     short            unused4;
  66. } OneStyle;
  67.  
  68. typedef struct
  69. {
  70.     short        numStyles;
  71.     OneStyle    theStyle[31];
  72. } StylRec, *StylPtr, **StylHandle;
  73.  
  74. enum
  75. {
  76.     kLeft=0,
  77.     kCenter
  78. };
  79.  
  80. short            gNumMainTopics;
  81. short            gNumSubTopics[MAX_MAIN_TOPICS];
  82.  
  83. CIconHandle        gMainTopicIconColor[MAX_MAIN_TOPICS];
  84. Handle            gMainTopicIconBW[MAX_MAIN_TOPICS];
  85. Str31            gMainTopicTitle[MAX_MAIN_TOPICS];
  86. Rect            gMainTopicRect[MAX_MAIN_TOPICS];
  87.  
  88. CIconHandle        gSubTopicIconColor[MAX_MAIN_TOPICS][MAX_SUB_TOPICS];
  89. Handle            gSubTopicIconBW[MAX_MAIN_TOPICS][MAX_SUB_TOPICS];
  90. Str31            gSubTopicTitle[MAX_MAIN_TOPICS][MAX_SUB_TOPICS];
  91. Rect            gSubTopicRect[MAX_MAIN_TOPICS][MAX_SUB_TOPICS];
  92.  
  93. short            gStickyTopic;
  94. short            gStickySubTopic;
  95.  
  96. short            gMainTopicShowing;        /* saved in prefs file */
  97. short            gSubTopicShowing;        /* saved in prefs file */
  98.  
  99. Rect            gTextRect;
  100. CharHandle        gTheText;
  101. StylHandle        gTheStyle;
  102.  
  103. /*-----------------------------------------------------------------------------------*/
  104. /* internal stuff for help.c                                                         */
  105.  
  106. void SetupTheHelpWindow(WindowDataHandle theData);
  107. void ShutdownTheHelpWindow(WindowDataHandle theData);
  108. void InitializeTheHelpWindow(WindowDataHandle theData);
  109. void OpenTheHelpWindow(WindowDataHandle theData);
  110. void KeyPressedInHelpWindow(WindowDataHandle theData, unsigned char keyPressed);
  111. void MouseClickedInHelpWindow(WindowDataHandle theData, Point mouseLoc);
  112. void DrawTheHelpWindow(short theDepth);
  113. void DrawTheText(CharHandle theText, StylHandle theStyleHandle, short theJust,
  114.     short theMode, Rect theRect);
  115. void DrawTheShadowBox(Rect theRect);
  116. short ParseRawTitle(Str255 theTitle);
  117. void GoToPage(WindowDataHandle theData, short mainTopic, short subTopic,
  118.     Boolean updateNow);
  119. void PushInSubTopic(WindowDataHandle theData);
  120. void PullOutSubTopic(WindowDataHandle theData, short mainTopic);
  121. void HighlightSubTopic(WindowDataHandle theData, short mainTopic, short subTopic,
  122.     Boolean isHighlighted);
  123. void GetTextResources(short mainTopic, short subTopic);
  124. void DisposeTextResources(void);
  125. void FullScrollRight(GrafPtr sourceGrafPtr, GrafPtr destGrafPtr, Rect boundsRect);
  126.  
  127.  
  128. short HelpWindowDispatch(WindowDataHandle theData, short theMessage, unsigned long misc)
  129. {
  130.     unsigned char    theChar;
  131.     Point            thePoint;
  132.     short            theDepth;
  133.     
  134.     switch (theMessage)
  135.     {
  136.         case kUpdate:
  137.             theDepth=misc&0x7fff;
  138.             DrawTheHelpWindow(theDepth);
  139.             return kSuccess;
  140.             break;
  141.         case kKeydown:
  142.             theChar=misc&charCodeMask;
  143.             KeyPressedInHelpWindow(theData, theChar);
  144.             return kSuccess;
  145.             break;
  146.         case kMousedown:
  147.             thePoint.h=(misc>>16)&0x7fff;
  148.             thePoint.v=misc&0x7fff;
  149.             MouseClickedInHelpWindow(theData, thePoint);
  150.             return kSuccess;
  151.             break;
  152.         case kOpen:
  153.             OpenTheHelpWindow(theData);
  154.             return kSuccess;
  155.             break;
  156.         case kInitialize:
  157.             InitializeTheHelpWindow(theData);
  158.             return kSuccess;
  159.             break;
  160.         case kStartup:
  161.             SetupTheHelpWindow(theData);
  162.             return kSuccess;
  163.             break;
  164.         case kShutdown:
  165.             ShutdownTheHelpWindow(theData);
  166.             return kSuccess;
  167.             break;
  168.     }
  169.     
  170.     return kFailure;        /* revert to default processing for all other messages */
  171. }
  172.  
  173. void SetupTheHelpWindow(WindowDataHandle theData)
  174. {
  175.     short            i,j;
  176.     unsigned char    *helpStr="\pHelp";
  177.     Handle            temp;
  178.     short            iconID;
  179.     short            centeringOffset;
  180.     
  181.     temp=GetResource('STR#', MAIN_TOPIC_ID);
  182.     gNumMainTopics=**((short**)temp);
  183.     ReleaseResource(temp);
  184.     for (i=0; i<gNumMainTopics; i++)
  185.     {
  186.         temp=GetResource('STR#', FIRST_SUB_TOPIC_ID+i);
  187.         gNumSubTopics[i]=**((short**)temp);
  188.         ReleaseResource(temp);
  189.     }
  190.     centeringOffset=(DEAD_SPACE_TOP+TEXT_RECT_HEIGHT+DEAD_SPACE_BOTTOM-
  191.         (gNumMainTopics*BUTTON_HEIGHT))/2;
  192.     for (i=0; i<gNumMainTopics; i++)
  193.     {
  194.         GetIndString(gMainTopicTitle[i], MAIN_TOPIC_ID, i+1);
  195.         iconID=ParseRawTitle(gMainTopicTitle[i]);
  196.         if (gHasColorQD)
  197.             gMainTopicIconColor[i]=GetCIcon(iconID);
  198.         gMainTopicIconBW[i]=GetIcon(iconID);
  199.         SetRect(&gMainTopicRect[i], DEAD_SPACE_LEFT, centeringOffset+BUTTON_HEIGHT*i,
  200.             DEAD_SPACE_LEFT+BUTTON_WIDTH, centeringOffset+BUTTON_HEIGHT*(i+1));
  201.         
  202.         for (j=0; j<gNumSubTopics[i]; j++)
  203.         {
  204.             GetIndString(gSubTopicTitle[i][j], FIRST_SUB_TOPIC_ID+i, j+1);
  205.             iconID=ParseRawTitle(gSubTopicTitle[i][j]);
  206.             if (gHasColorQD)
  207.                 gSubTopicIconColor[i][j]=GetCIcon(iconID);
  208.             gSubTopicIconBW[i][j]=GetIcon(iconID);
  209.             SetRect(&gSubTopicRect[i][j], DEAD_SPACE_LEFT+BUTTON_WIDTH*(j+1),
  210.                 centeringOffset+BUTTON_HEIGHT*i, DEAD_SPACE_LEFT+BUTTON_WIDTH*(j+2),
  211.                 centeringOffset+BUTTON_HEIGHT*(i+1));
  212.         }
  213.     }
  214.     
  215.     gTheText=gTheStyle=0L;
  216.     GoToPage(0L, gMainTopicShowing, gSubTopicShowing, FALSE);
  217.     
  218.     SetRect(&gTextRect, DEAD_SPACE_LEFT+BUTTON_WIDTH+DEAD_SPACE_LEFT, DEAD_SPACE_TOP,
  219.         DEAD_SPACE_LEFT+BUTTON_WIDTH+DEAD_SPACE_LEFT+TEXT_RECT_WIDTH,
  220.         DEAD_SPACE_TOP+TEXT_RECT_HEIGHT);
  221.     
  222.     (**theData).maxDepth=8;
  223.     (**theData).windowWidth=DEAD_SPACE_LEFT+BUTTON_WIDTH+DEAD_SPACE_LEFT+
  224.         TEXT_RECT_WIDTH+DEAD_SPACE_RIGHT;
  225.     (**theData).windowHeight=DEAD_SPACE_TOP+TEXT_RECT_HEIGHT+DEAD_SPACE_BOTTOM;
  226.     (**theData).windowType=noGrowDocProc;    /* document-looking thing */
  227.     (**theData).hasCloseBox=TRUE;
  228.     (**theData).windowBounds.top=50;
  229.     (**theData).windowBounds.left=6;
  230.     Mymemcpy((Ptr)((**(gTheWindowData[kHelp])).windowTitle), (Ptr)helpStr, helpStr[0]+1);
  231. }
  232.  
  233. void ShutdownTheHelpWindow(WindowDataHandle theData)
  234. {
  235.     short            i,j;
  236.     
  237.     for (i=0; i<gNumMainTopics; i++)
  238.     {
  239.         if (gHasColorQD)
  240.             DisposeCIcon(gMainTopicIconColor[i]);
  241.         ReleaseResource(gMainTopicIconBW[i]);
  242.         
  243.         for (j=0; j<gNumSubTopics[i]; j++)
  244.         {
  245.             if (gHasColorQD)
  246.                 DisposeCIcon(gSubTopicIconColor[i][j]);
  247.             ReleaseResource(gSubTopicIconColor[i][j]);
  248.         }
  249.     }
  250.     DisposeTextResources();
  251. }
  252.  
  253. void InitializeTheHelpWindow(WindowDataHandle theData)
  254. {
  255.     (**theData).initialTopLeft.v=(**theData).windowBounds.top-9;
  256.     (**theData).initialTopLeft.h=(**theData).windowBounds.left;
  257.     gStickyTopic=-1;
  258. }
  259.  
  260. void OpenTheHelpWindow(WindowDataHandle theData)
  261. {
  262.     (**theData).offscreenNeedsUpdate=TRUE;
  263. }
  264.  
  265. void KeyPressedInHelpWindow(WindowDataHandle theData, unsigned char keyPressed)
  266. {
  267.     short            oldTopic;
  268.     
  269.     ObscureCursor();
  270.     
  271.     switch (keyPressed)
  272.     {
  273.         case 0x1d:                                        /* right arrow */
  274.             if (gStickyTopic==-1)
  275.             {
  276.                 gSubTopicShowing++;
  277.                 if (gSubTopicShowing>=gNumSubTopics[gMainTopicShowing])
  278.                 {
  279.                     gSubTopicShowing=0;
  280.                     gMainTopicShowing++;
  281.                     if (gMainTopicShowing>=gNumMainTopics)
  282.                         gMainTopicShowing=0;
  283.                 }
  284.                 GoToPage(theData, gMainTopicShowing, gSubTopicShowing, TRUE);
  285.             }
  286.             else
  287.             {
  288.                 if (gStickySubTopic!=-1)
  289.                     HighlightSubTopic(theData, gStickyTopic, gStickySubTopic, FALSE);
  290.                 gStickySubTopic++;
  291.                 if (gStickySubTopic>=gNumSubTopics[gStickyTopic])
  292.                     gStickySubTopic=0;
  293.                 HighlightSubTopic(theData, gStickyTopic, gStickySubTopic, TRUE);
  294.             }
  295.             break;
  296.         case 0x1c:                                        /* left arrow */
  297.             if (gStickyTopic==-1)
  298.             {
  299.                 gSubTopicShowing--;
  300.                 if (gSubTopicShowing<0)
  301.                 {
  302.                     gMainTopicShowing--;
  303.                     if (gMainTopicShowing<0)
  304.                         gMainTopicShowing=gNumMainTopics-1;
  305.                     gSubTopicShowing=gNumSubTopics[gMainTopicShowing]-1;
  306.                 }
  307.                 GoToPage(theData, gMainTopicShowing, gSubTopicShowing, TRUE);
  308.             }
  309.             else
  310.             {
  311.                 if (gStickySubTopic!=-1)
  312.                     HighlightSubTopic(theData, gStickyTopic, gStickySubTopic, FALSE);
  313.                 gStickySubTopic--;
  314.                 if (gStickySubTopic<0)
  315.                     gStickySubTopic=gNumSubTopics[gStickyTopic]-1;
  316.                 HighlightSubTopic(theData, gStickyTopic, gStickySubTopic, TRUE);
  317.             }
  318.             break;
  319.         case 0x1e:                                        /* up arrow */
  320.             if (gStickyTopic!=-1)
  321.             {
  322.                 oldTopic=gStickyTopic;
  323.                 PushInSubTopic(theData);
  324.                 gStickyTopic=oldTopic-1;
  325.                 if (gStickyTopic<0)
  326.                     gStickyTopic=gNumMainTopics-1;
  327.             }
  328.             else gStickyTopic=gNumMainTopics-1;
  329.             
  330.             PullOutSubTopic(theData, gStickyTopic);
  331.             break;
  332.         case 0x1f:                                        /* down arrow */
  333.             if (gStickyTopic!=-1)
  334.             {
  335.                 oldTopic=gStickyTopic;
  336.                 PushInSubTopic(theData);
  337.                 gStickyTopic=oldTopic+1;
  338.                 if (gStickyTopic>=gNumMainTopics)
  339.                     gStickyTopic=0;
  340.             }
  341.             else gStickyTopic=0;
  342.             
  343.             PullOutSubTopic(theData, gStickyTopic);
  344.             break;
  345.         case 0x1b:                                        /* escape key */
  346.             if (gStickyTopic!=-1)
  347.                 PushInSubTopic(theData);
  348.             else CloseTheWindow(theData);
  349.             break;
  350.         case 0x03:
  351.         case 0x0d:
  352.             if (gStickyTopic==-1)
  353.             {
  354.                 gStickyTopic=gMainTopicShowing;
  355.                 PullOutSubTopic(theData, gStickyTopic);
  356.             }
  357.             else
  358.             {
  359.                 if (gStickySubTopic!=-1)
  360.                 {
  361.                     HighlightSubTopic(theData, gStickyTopic, gStickySubTopic, FALSE);
  362.                     GoToPage(theData, gStickyTopic, gStickySubTopic, TRUE);
  363.                 }
  364.                 else PushInSubTopic(theData);
  365.             }
  366.             break;
  367.     }
  368. }
  369.  
  370. void MouseClickedInHelpWindow(WindowDataHandle theData, Point mouseLoc)
  371. {
  372.     short            newTopic;
  373.     Boolean            isColor;
  374.     short            i;
  375.     
  376.     isColor=((**theData).windowDepth>2);
  377.     newTopic=-1;
  378.     
  379.     for (i=0; i<gNumMainTopics; i++)
  380.     {
  381.         if (PtInRect(mouseLoc, &gMainTopicRect[i]))
  382.         {
  383.             newTopic=i;
  384.             i=gNumMainTopics;
  385.         }
  386.     }
  387.     
  388.     if (newTopic!=-1)
  389.     {
  390.         if (newTopic==gStickyTopic)
  391.             PushInSubTopic(theData);
  392.         else
  393.         {
  394.             if (gStickyTopic!=-1)
  395.                 PushInSubTopic(theData);
  396.             PullOutSubTopic(theData, newTopic);
  397.             gStickyTopic=newTopic;
  398.         }
  399.     }
  400.     
  401.     if ((gStickyTopic!=-1) && (newTopic==-1))
  402.     {
  403.         for (i=0; i<gNumSubTopics[gStickyTopic]; i++)
  404.         {
  405.             if (PtInRect(mouseLoc, &gSubTopicRect[gStickyTopic][i]))
  406.             {
  407.                 if (gStickySubTopic!=-1)
  408.                     HighlightSubTopic(theData, gStickyTopic, gStickySubTopic, FALSE);
  409.                 gStickySubTopic=-1;
  410.                 
  411.                 if (Track3DButton(&gSubTopicRect[gStickyTopic][i],
  412.                     gSubTopicTitle[gStickyTopic][i], isColor ?
  413.                     (Handle)gSubTopicIconColor[gStickyTopic][i] :
  414.                     gSubTopicIconBW[gStickyTopic][i], (**theData).windowDepth))
  415.                 {
  416.                     newTopic=i;
  417.                     i=gNumSubTopics[gStickyTopic];
  418.                 }
  419.             }
  420.         }
  421.         if (newTopic!=-1)
  422.             GoToPage(theData, gStickyTopic, newTopic, TRUE);
  423.         else
  424.             PushInSubTopic(theData);
  425.     }
  426. }
  427.  
  428. void DrawTheHelpWindow(short theDepth)
  429. {
  430.     GrafPtr            curPort;
  431.     short            i,j;
  432.     Boolean            isColor;
  433.     Rect            tempRect;
  434.     
  435.     isColor=(theDepth>2);
  436.     
  437.     GetPort(&curPort);
  438.     EraseRect(&(curPort->portRect));
  439.     
  440.     DrawTheShadowBox(gTextRect);
  441.     if (gTheText!=0L)
  442.     {
  443.         tempRect=gTextRect;
  444.         InsetRect(&tempRect, 8, 4);
  445.         DrawTheText(gTheText, gTheStyle, kLeft, srcOr, tempRect);
  446.     }
  447.     
  448.     for (i=0; i<gNumMainTopics; i++)
  449.     {
  450.         Draw3DButton(&gMainTopicRect[i], gMainTopicTitle[i],
  451.             isColor ? (Handle)gMainTopicIconColor[i] : gMainTopicIconBW[i],
  452.             theDepth, (i==gStickyTopic));
  453.         if (i==gStickyTopic)
  454.         {
  455.             for (j=0; j<gNumSubTopics[i]; j++)
  456.             {
  457.                 Draw3DButton(&gSubTopicRect[i][j], gSubTopicTitle[i][j],
  458.                 isColor ? (Handle)gSubTopicIconColor[i][j] : gSubTopicIconBW[i][j],
  459.                 theDepth, (j==gStickySubTopic));
  460.             }
  461.         }
  462.     }
  463. }
  464.  
  465. void DrawTheText(CharHandle theText, StylHandle theStyleHandle, short theJust,
  466.     short theMode, Rect theRect)
  467. {
  468.     short            i, numStyles;
  469.     long            textPos;
  470.     long            maxOffset;
  471.     Str255            thisLine;
  472.     Boolean            notDoneYet;
  473.     unsigned char    thisChar;
  474.     short            theRow, theCol;
  475.     unsigned char    lastEnd, thisEnd;
  476.     Boolean            overRun;
  477.     
  478.     numStyles=(**theStyleHandle).numStyles;
  479.     textPos=0L;
  480.     theRow=theRect.top+(**theStyleHandle).theStyle[0].fontDescent+1;
  481.     theCol=theRect.left;
  482.     thisLine[0]=0x00;
  483.     lastEnd=0;
  484.     for (i=0; i<numStyles; i++)
  485.     {
  486.         if (i==numStyles-1)
  487.             maxOffset=GetHandleSize(theText);
  488.         else
  489.             maxOffset=(**theStyleHandle).theStyle[i+1].offset;
  490.         
  491.         TextFont((**theStyleHandle).theStyle[i].fontNum);
  492.         TextFace((**theStyleHandle).theStyle[i].fontStyle);
  493.         TextSize((**theStyleHandle).theStyle[i].fontSize);
  494.         TextMode(theMode);
  495.         
  496.         while (textPos<maxOffset)
  497.         {
  498.             notDoneYet=TRUE;
  499.             while ((textPos<maxOffset) && (notDoneYet))
  500.             {
  501.                 thisChar=thisLine[++thisLine[0]]=(*theText)[textPos++];
  502.                 notDoneYet=((thisChar!=' ') && (thisChar!=0x0d));
  503.             }
  504.             
  505.             thisEnd=thisLine[0];
  506.             overRun=(theRect.right-theCol<=StringWidth(thisLine));
  507.             
  508.             if ((overRun) || (thisChar==0x0d) || (textPos==maxOffset))
  509.             {
  510.                 if (overRun)
  511.                     thisLine[0]=lastEnd;
  512.                 if (theJust==kCenter)
  513.                     MoveTo((theRect.right-theRect.left-StringWidth(thisLine))/2+
  514.                             theCol, theRow);
  515.                 else
  516.                     MoveTo(theCol, theRow);
  517.                 theCol+=StringWidth(thisLine);
  518.                 DrawString(thisLine);
  519.                 if (overRun)
  520.                 {
  521.                     BlockMove(&thisLine[lastEnd+1], &thisLine[1], thisEnd-lastEnd+1);
  522.                     if (thisEnd>=lastEnd)
  523.                     {
  524.                         thisLine[0]=thisEnd-lastEnd-1;
  525.                         textPos--;
  526.                     }
  527.                     else
  528.                         thisEnd=thisLine[0]=0x00;
  529.                 }
  530.                 else thisLine[0]=0x00;
  531.                 if ((overRun) || (thisChar==0x0d))
  532.                 {
  533.                     theRow+=(**theStyleHandle).theStyle[i].lineHeight;
  534.                     theCol=theRect.left;
  535.                 }
  536.             }
  537.             
  538.             lastEnd=thisEnd;
  539.         }
  540.         
  541.         if (thisLine[0]!=0x00)
  542.         {
  543.             if (theJust==kCenter)
  544.                 MoveTo((theRect.right-theRect.left-StringWidth(thisLine))/2+
  545.                         theCol, theRow);
  546.             else
  547.                 MoveTo(theCol, theRow);
  548.             theCol+=StringWidth(thisLine);
  549.             DrawString(thisLine);
  550.             thisLine[0]=0x00;
  551.         }
  552.     }
  553.     TextMode(srcOr);
  554. }
  555.  
  556. void DrawTheShadowBox(Rect theRect)
  557. {
  558.     theRect.right-=2;
  559.     theRect.bottom-=2;
  560.     FrameRect(&theRect);
  561.     MoveTo(theRect.left+3, theRect.bottom+1);
  562.     Line(theRect.right-theRect.left-2, 0);
  563.     Line(0, -theRect.bottom+theRect.top+3);
  564.     MoveTo(theRect.left+3, theRect.bottom);
  565.     Line(theRect.right-theRect.left-3, 0);
  566.     Line(0, -theRect.bottom+theRect.top+4);
  567. }
  568.  
  569. short ParseRawTitle(Str255 theTitle)
  570. {
  571.     Str255            numStr;
  572.     unsigned long    result;
  573.     
  574.     numStr[0]=0x00;
  575.     while ((numStr[numStr[0]]=theTitle[++numStr[0]])!=' ') {}
  576.     theTitle[0]-=numStr[0];
  577.     Mymemcpy(&theTitle[1], &theTitle[numStr[0]+1], theTitle[0]);
  578.     numStr[0]--;
  579.     StringToNum(numStr, &result);
  580.     return result;
  581. }
  582.  
  583. void GoToPage(WindowDataHandle theData, short mainTopic, short subTopic,
  584.     Boolean updateNow)
  585. {
  586.     DisposeTextResources();
  587.     GetTextResources(mainTopic, subTopic);
  588.     gMainTopicShowing=mainTopic;
  589.     gSubTopicShowing=subTopic;
  590.     gStickyTopic=gStickySubTopic=-1;
  591.     if (updateNow)
  592.     {
  593.         (**theData).offscreenNeedsUpdate=TRUE;
  594.         UpdateTheWindow(theData);
  595.     }
  596. }
  597.  
  598. void PushInSubTopic(WindowDataHandle theData)
  599. {
  600.     gStickyTopic=-1;
  601.     (**theData).offscreenNeedsUpdate=TRUE;
  602.     UpdateTheWindow(theData);
  603. }
  604.  
  605. void PullOutSubTopic(WindowDataHandle theData, short mainTopic)
  606. {
  607.     short            i;
  608.     short            theDepth;
  609.     Boolean            isColor;
  610.     Rect            tempRect;
  611.     
  612.     gStickySubTopic=-1;
  613.     
  614.     isColor=(theDepth=(**theData).windowDepth)>2;
  615.     
  616.     SetPortToOffscreen(theData);
  617.     for (i=0; i<gNumSubTopics[mainTopic]; i++)
  618.     {
  619.         Draw3DButton(&gSubTopicRect[mainTopic][i], gSubTopicTitle[mainTopic][i],
  620.         isColor ? (Handle)gSubTopicIconColor[mainTopic][i] :
  621.         gSubTopicIconBW[mainTopic][i], theDepth, FALSE);
  622.     }
  623.     RestorePortToScreen(theData);
  624.  
  625.     Draw3DButton(&gMainTopicRect[mainTopic], gMainTopicTitle[mainTopic],
  626.         isColor ? (Handle)gMainTopicIconColor[mainTopic] :
  627.         gMainTopicIconBW[mainTopic], theDepth, TRUE);
  628.     
  629.     tempRect=gSubTopicRect[mainTopic][0];
  630.     tempRect.right=gSubTopicRect[mainTopic][gNumSubTopics[mainTopic]-1].right;
  631.     FullScrollRight(GetOffscreenGrafPtr(theData), GetWindowGrafPtr(theData), tempRect);
  632.     
  633.     (**theData).offscreenNeedsUpdate=TRUE;
  634. }
  635.  
  636. void HighlightSubTopic(WindowDataHandle theData, short mainTopic, short subTopic,
  637.     Boolean isHighlighted)
  638. {
  639.     Draw3DButton(&gSubTopicRect[mainTopic][subTopic], gSubTopicTitle[mainTopic][subTopic],
  640.         ((**theData).windowDepth>2) ? (Handle)gSubTopicIconColor[mainTopic][subTopic] :
  641.         gSubTopicIconBW[mainTopic][subTopic], (**theData).windowDepth, isHighlighted);
  642.     
  643.     (**theData).offscreenNeedsUpdate=TRUE;
  644. }
  645.  
  646. void GetTextResources(short mainTopic, short subTopic)
  647. {
  648.     short            i;
  649.     short            resID;
  650.     
  651.     DisposeTextResources();
  652.     resID=FIRST_TEXT_ID;
  653.     for (i=0; i<mainTopic; i++)
  654.         resID+=gNumSubTopics[i];
  655.     resID+=subTopic;
  656.     gTheText=GetResource('TEXT', resID);
  657.     gTheStyle=GetResource('styl', resID);
  658. }
  659.  
  660. void DisposeTextResources(void)
  661. {
  662.     if (gTheText!=0L)
  663.         ReleaseResource(gTheText);
  664.     if (gTheStyle!=0L)
  665.         ReleaseResource(gTheStyle);
  666.     gTheText=gTheStyle=0L;
  667. }
  668.  
  669. void FullScrollRight(GrafPtr sourceGrafPtr, GrafPtr destGrafPtr, Rect boundsRect)
  670. {
  671.     Rect            sourceRect, destRect, scrollRect;
  672.     short            BoxSize;
  673.     
  674.     StartTiming();
  675.     
  676.     BoxSize=SCROLL_BOX_SIZE;
  677.     
  678.     destRect=sourceRect=scrollRect=boundsRect;
  679.     destRect.right=destRect.left+BoxSize;
  680.     sourceRect.left=boundsRect.right-BoxSize;
  681.     scrollRect.right=scrollRect.left+2*BoxSize;
  682.     
  683.     CopyBits(&(sourceGrafPtr->portBits), &(destGrafPtr->portBits),
  684.         &sourceRect, &destRect, 0, 0L);
  685.     
  686.     TimeCorrection(CorrectTime);
  687.     
  688.     while (scrollRect.right<=boundsRect.right)
  689.     {
  690.         StartTiming();
  691.         sourceRect.right-=BoxSize;
  692.         sourceRect.left-=BoxSize;
  693.         ScrollTheRect(&scrollRect, BoxSize, 0, 0L);
  694.         CopyBits(&(sourceGrafPtr->portBits), &(destGrafPtr->portBits),
  695.             &sourceRect, &destRect, 0, 0L);
  696.         TimeCorrection(CorrectTime);
  697.         scrollRect.right+=BoxSize;
  698.     }
  699.     
  700.     if (scrollRect.right!=boundsRect.right)
  701.         CopyBits(&(sourceGrafPtr->portBits), &(destGrafPtr->portBits),
  702.             &boundsRect, &boundsRect, 0, 0L);
  703. }
  704.